﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using GalaSoft.MvvmLight;
using RPGOnline.Remoting;
using RPGOnline.Remoting.Entities;
using RPGOnline.Remoting.Events;
using RPGOnlineWPF.Model.Interfaces;

namespace RPGOnlineWPF.ViewModel
{
	public class ChatViewModel : ViewModelBase
	{
		private readonly IChatService m_chatService;
		private readonly ChatManager m_chatManager;
		private GroupManager m_groupsManager;
		private SessionContext m_sessionContext;
		private UserManager m_userManager;

		public ChatViewModel(IChatService chatService)
		{
			Groups = new ObservableCollection<ChatGroupViewModel>();
			Conversations = new ObservableCollection<ChatConversationViewModel>();

			if (IsInDesignMode)
			{
				ChatGroup cg = new ChatGroup("Main Chat", Guid.NewGuid());
				ChatGroup cg1 = new ChatGroup("Secondary Chat", Guid.NewGuid());

				Conversations.Add(new ChatConversationViewModel(chatService, cg));
				Conversations.Add(new ChatConversationViewModel(chatService, cg1));

				User u = new User("Design", new System.Drawing.Font("Microsoft Sans Serif", 8), System.Drawing.Color.DarkMagenta);
				User u1 = new User("Design1", new System.Drawing.Font("Microsoft Sans Serif", 8), System.Drawing.Color.DarkBlue);
				User u2 = new User("Design2", new System.Drawing.Font("Microsoft Sans Serif", 8), System.Drawing.Color.DarkGreen);
				User u3 = new User("Design3", new System.Drawing.Font("Microsoft Sans Serif", 8), System.Drawing.Color.DarkRed);
				User u4 = new User("Design4", new System.Drawing.Font("Microsoft Sans Serif", 8), System.Drawing.Color.DarkCyan);
				User u5 = new User("Design5", new System.Drawing.Font("Microsoft Sans Serif", 8), System.Drawing.Color.DarkGoldenrod);

				OnUserAddedToGroup(this, new UserGroupEventArgs(u, cg));
				OnUserAddedToGroup(this, new UserGroupEventArgs(u1, cg));
				OnUserAddedToGroup(this, new UserGroupEventArgs(u2, cg));
				OnUserAddedToGroup(this, new UserGroupEventArgs(u3, cg));
				OnUserAddedToGroup(this, new UserGroupEventArgs(u4, cg1));
				OnUserAddedToGroup(this, new UserGroupEventArgs(u5, cg1));

				OnMessageReceived(this, new MessageReceivedEventArgs(cg.Id, u, "Corto corto"));
				OnMessageReceived(this, new MessageReceivedEventArgs(cg.Id, u1, "Pellentesque habitant morbi tristique"));

				OnUserRolled(cg, u1, new RollResult(2,6,3,11));

				OnMessageReceived(this, new MessageReceivedEventArgs(cg.Id, u2, "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo."));
				OnMessageReceived(this, new MessageReceivedEventArgs(cg.Id, u3, "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus"));
			}
			else
			{
				m_chatService = chatService;
				m_chatManager = chatService.GetChatManager();
				m_sessionContext = chatService.GetSessionContext();
				m_userManager = chatService.GetUserManager();
				m_groupsManager = chatService.GetGroupManager();

				m_groupsManager.OnGroupAdded += OnGroupAdded;
				m_groupsManager.OnGroupRemoved += OnGroupRemoved;
				m_groupsManager.OnUserAddedToGroup += OnUserAddedToGroup;
				m_groupsManager.OnUserInfoChanged += OnUserInfoChanged;
				m_groupsManager.OnUserRemovedFromGroup += OnUserRemovedFromGroup;

				m_chatManager.OnMessageReceived += OnMessageReceived;
				m_chatManager.OnUserRegistered += OnUserRegistered;
				m_chatManager.OnUserUnregistered += OnUserUnregistered;
				m_chatManager.OnUserRolled += OnUserRolled;

				m_chatManager.OnRegistrationFailed += OnRegistrationFailed;
				m_chatManager.Notify.RegisterUser(m_userManager.CurrentUser, true);
				m_chatManager.Notify.RequestSessionUpdate();
			}
		}

		private void OnUserRolled(object sender, UserRollEventArgs e)
		{
			var userGroup = m_sessionContext.FindGroupByUser(e.User);
			if (userGroup == null)
				return;

			OnUserRolled(userGroup, e.User, e.RollResult);
		}

		private void OnUserRolled(ChatGroup userGroup, User user, RollResult rollResult)
		{
			var conversation = CreateOrGetConversation(userGroup.Id);
			if (conversation != null)
				conversation.AddDiceRoll(user, rollResult);
		}

		private void OnUserUnregistered(object sender, UserRegistrationEventArgs e)
		{
			var conversation = CreateOrGetConversation(e.ChatGroup);
			if (conversation != null)
				conversation.AddSystemMessage(e.User.Name + " leaved the chat!");
		}

		private void OnUserRegistered(object sender, UserRegistrationEventArgs e)
		{
			var conversation = CreateOrGetConversation(e.ChatGroup);
			if (conversation != null)
				conversation.AddSystemMessage(e.User.Name + " entered the chat!");
		}

		private void OnMessageReceived(object sender, MessageReceivedEventArgs e)
		{
			var conversation = CreateOrGetConversation(e.ChatGroupId);
			if(conversation != null)
				conversation.AddMessage(e.User, e.Message);
		}

		private ChatConversationViewModel CreateOrGetConversation(Guid chatGroupId)
		{
			var conversation = Conversations.FirstOrDefault(c => c.Id == chatGroupId);
			if (conversation == null)
			{
				var chatGroup = m_sessionContext.FindGroupById(chatGroupId);
				if (chatGroup == null)
					return null;

				Conversations.Add(conversation = new ChatConversationViewModel(m_chatService, chatGroup));
			}
			return conversation;
		}

		private void OnUserRemovedFromGroup(object sender, UserGroupEventArgs e)
		{
			var chatGroup = Groups.FirstOrDefault(g => g.Id == e.Group.Id);

			if (chatGroup == null)
				Groups.Add(chatGroup = new ChatGroupViewModel(e.Group));

			chatGroup.RemoveUser(e.User);
		}

		private void OnUserInfoChanged(object sender, UserGroupEventArgs e)
		{
			var chatGroup = Groups.FirstOrDefault(g => g.Id == e.Group.Id);

			if (chatGroup == null)
				Groups.Add(chatGroup = new ChatGroupViewModel(e.Group));

			chatGroup.UpdateUser(e.User);
		}

		private void OnRegistrationFailed(object sender, EventArgs e)
		{
			MessageBox.Show("Failed to connect!");
		}

		private void OnUserAddedToGroup(object sender, UserGroupEventArgs e)
		{
			var chatGroup = Groups.FirstOrDefault(g => g.Id == e.Group.Id);
			
			if(chatGroup == null)
				Groups.Add(chatGroup = new ChatGroupViewModel(e.Group));
			
			chatGroup.AddUser(e.User);
		}

		private void OnGroupRemoved(object sender, GroupEventArgs e)
		{
			var chatGroup = Groups.FirstOrDefault(g => g.Id == e.Group.Id);
			if (chatGroup != null)
				Groups.Remove(chatGroup);
		}

		private void OnGroupAdded(object sender, GroupEventArgs e)
		{
			Groups.Add(new ChatGroupViewModel(e.Group));
		}

		public ObservableCollection<ChatGroupViewModel> Groups
		{
			get; private set;
		}

		public ObservableCollection<ChatConversationViewModel> Conversations
		{
			get; private set;
		}
	}
}